Reactã®Render Propsãã¿ãŒã³ã®åãè§£ãæŸã¡ãŸããããã³ãŒãã®åå©çšæ§ãã³ã³ããŒãã³ãã®åæãé¢å¿ã®åé¢ãä¿é²ããåœéçãªå©çšè ã®ããã®æè»ã§ä¿å®æ§ã®é«ãã¢ããªã±ãŒã·ã§ã³ãå®çŸããæ¹æ³ãåŠã³ãŸãã
React Render Propsãã¿ãŒã³ïŒã°ããŒãã«ãªå©çšè ã察象ãšããæè»ãªã³ã³ããŒãã³ãããžãã¯
é²åãç¶ããããã³ããšã³ãéçºãç¹ã«Reactãšã³ã·ã¹ãã ã®äžçã«ãããŠãã¢ãŒããã¯ãã£ãã¿ãŒã³ã¯ãã¹ã±ãŒã©ãã«ã§ä¿å®æ§ãé«ããåå©çšå¯èœãªã³ã³ããŒãã³ããæ§ç¯ããäžã§éèŠãªåœ¹å²ãæãããŸãããããã®ãã¿ãŒã³ã®äžã§ããRender Propsãã¿ãŒã³ã¯ãReactã³ã³ããŒãã³ãéã§ã³ãŒããšããžãã¯ãå ±æããããã®åŒ·åãªãã¯ããã¯ãšããŠéç«ã£ãŠããŸãããã®ããã°èšäºã§ã¯ãRender Propsãã¿ãŒã³ã®å æ¬çãªçè§£ããã®å©ç¹ããŠãŒã¹ã±ãŒã¹ããããŠãããã°ããŒãã«ãªå©çšè ã®ããã®å ç¢ã§é©å¿æ§ã®é«ãã¢ããªã±ãŒã·ã§ã³ã®æ§ç¯ã«ã©ã®ããã«è²¢ç®ããããæäŸããããšãç®çãšããŠããŸãã
Render Propsãšã¯ïŒ
Render Propãšã¯ãå€ã颿°ã§ããpropã䜿çšããŠReactã³ã³ããŒãã³ãéã§ã³ãŒããå ±æããããã®ã·ã³ãã«ãªãã¯ããã¯ã§ããæ¬è³ªçã«ãrender propãæã€ã³ã³ããŒãã³ãã¯ãReactèŠçŽ ãè¿ã颿°ãåãåãããã®é¢æ°ãåŒã³åºããŠäœããæç»ããŸããã³ã³ããŒãã³ãã¯çŽæ¥äœãã¬ã³ããªã³ã°ããããæ±ºå®ããããã®æ±ºå®ãrender prop颿°ã«å§ä»»ããå éšã®ç¶æ ãšããžãã¯ãžã®ã¢ã¯ã»ã¹ãæäŸããŸãã
ãã®åºæ¬çãªäŸãèããŠã¿ãŸãããïŒ
class DataProvider extends React.Component {
constructor(props) {
super(props);
this.state = { data: null };
}
componentDidMount() {
// ããŒã¿ã®ãã§ãããã·ãã¥ã¬ãŒã
setTimeout(() => {
this.setState({ data: 'Some data from an API' });
}, 1000);
}
render() {
return this.props.render(this.state.data);
}
}
function MyComponent() {
return (
(
{data ? Data: {data}
: Loading...
}
)}
/>
);
}
ãã®äŸã§ã¯ãDataProvider
ãããŒã¿ããã§ãããããããMyComponent
ã«ãã£ãŠæäŸãããrender
prop颿°ã«æž¡ããŸããMyComponent
ã¯ãã®ããŒã¿ã䜿çšããŠã³ã³ãã³ããã¬ã³ããªã³ã°ããŸãã
ãªãRender Propsã䜿ãã®ãïŒ
Render Propsãã¿ãŒã³ã¯ãããã€ãã®éèŠãªå©ç¹ãæäŸããŸãïŒ
- ã³ãŒãã®åå©çšæ§ïŒ Render Propsã䜿çšãããšãè€æ°ã®ã³ã³ããŒãã³ãã«ããã£ãŠããžãã¯ãã«ãã»ã«åããåå©çšã§ããŸããã³ãŒããè€è£œãã代ããã«ãç¹å®ã®ã¿ã¹ã¯ãåŠçãããã®ããžãã¯ãrender propãä»ããŠå ±æããã³ã³ããŒãã³ããäœæã§ããŸãã
- ã³ã³ããŒãã³ãã®åæïŒ Render Propsã¯ãè€æ°ã®ã³ã³ããŒãã³ãããã®ç°ãªãæ©èœãåäžã®UIèŠçŽ ã«çµã¿åãããããšãå¯èœã«ããããšã§ãåæãä¿é²ããŸãã
- é¢å¿ã®åé¢ïŒ Render Propsã¯ãããžãã¯ããã¬ãŒã³ããŒã·ã§ã³ããåé¢ããããšã§ãé¢å¿ã®åé¢ã«åœ¹ç«ã¡ãŸããrender propãæäŸããã³ã³ããŒãã³ããããžãã¯ãåŠçããrender propã䜿çšããã³ã³ããŒãã³ããã¬ã³ããªã³ã°ãåŠçããŸãã
- æè»æ§ïŒ Render Propsã¯æ¯é¡ã®ãªãæè»æ§ãæäŸããŸããã³ã³ããŒãã³ãã®å©çšè ã¯ãããŒã¿ãšããžãã¯ã*ã©ã®ããã«*ã¬ã³ããªã³ã°ãããããå¶åŸ¡ãããããã³ã³ããŒãã³ãã¯ããŸããŸãªãŠãŒã¹ã±ãŒã¹ã«é«åºŠã«é©å¿ã§ããŸãã
å®äžçã®ãŠãŒã¹ã±ãŒã¹ãšåœéçãªäŸ
Render Propsãã¿ãŒã³ã¯ãããŸããŸãªã·ããªãªã§äŸ¡å€ããããŸãã以äžã«ãã°ããŒãã«ãªå©çšè ãèæ ®ããäŸãå«ãäžè¬çãªãŠãŒã¹ã±ãŒã¹ãããã€ã玹ä»ããŸãïŒ
1. ããŠã¹ãã©ããã³ã°
ãŠã§ãããŒãžäžã®ããŠã¹äœçœ®ã远跡ããããšæ³åããŠã¿ãŠãã ãããRender Propã䜿çšãããšãããŠã¹åº§æšããã®åã«æäŸããMouseTracker
ã³ã³ããŒãã³ããäœæã§ããŸãã
class MouseTracker extends React.Component {
constructor(props) {
super(props);
this.state = { x: 0, y: 0 };
}
handleMouseMove = event => {
this.setState({ x: event.clientX, y: event.clientY });
};
render() {
return (
{this.props.render(this.state)}
);
}
}
function MyComponent() {
return (
(
The mouse position is ({x}, {y})
)}
/>
);
}
ããã¯åœéåãããã¢ããªã±ãŒã·ã§ã³ã«ç°¡åã«é©å¿ã§ããŸããäŸãã°ãæ¥æ¬ã®ã¢ãŒãã£ã¹ãã䜿çšãããçµµããã¢ããªã±ãŒã·ã§ã³ãæ³åããŠã¿ãŠãã ãããããŠã¹åº§æšã¯ãã©ã·ã®ã¹ãããŒã¯ãå¶åŸ¡ããããã«äœ¿çšã§ããŸãïŒ
(
)}
/>
2. APIããã®ããŒã¿ãã§ãã
APIããããŒã¿ããã§ããããããšã¯ããŠã§ãéçºã«ãããäžè¬çãªã¿ã¹ã¯ã§ããRender Propã³ã³ããŒãã³ãã¯ãããŒã¿ãã§ããããžãã¯ãåŠçãããã®ããŒã¿ãåã«æäŸããããšãã§ããŸãã
class APIFetcher extends React.Component {
constructor(props) {
super(props);
this.state = { data: null, loading: true, error: null };
}
async componentDidMount() {
try {
const response = await fetch(this.props.url);
const data = await response.json();
this.setState({ data: data, loading: false });
} catch (error) {
this.setState({ error: error, loading: false });
}
}
render() {
return this.props.render(this.state);
}
}
function MyComponent() {
return (
{
if (loading) return Loading...
;
if (error) return Error: {error.message}
;
return {JSON.stringify(data, null, 2)}
;
}}
/>
);
}
ããã¯ãããŒã«ã©ã€ãºãããããŒã¿ãæ±ãå Žåã«ç¹ã«äŸ¿å©ã§ããäŸãã°ãç°ãªãå°åã®ãŠãŒã¶ãŒã«çºæ¿ã¬ãŒãã衚瀺ããå Žåãæ³åããŠã¿ãŠãã ããïŒ
{
if (loading) return Loading exchange rates...
;
if (error) return Error fetching exchange rates.
;
return (
{Object.entries(data.rates).map(([currency, rate]) => (
- {currency}: {rate}
))}
);
}}
/>
3. ãã©ãŒã ãã³ããªã³ã°
ãã©ãŒã ã®ç¶æ ãšããªããŒã·ã§ã³ã®ç®¡çã¯è€éã«ãªãããšããããŸããRender Propã³ã³ããŒãã³ãã¯ããã©ãŒã ããžãã¯ãã«ãã»ã«åãããã©ãŒã ã®ç¶æ ãšãã³ãã©ãŒããã®åã«æäŸããããšãã§ããŸãã
class FormHandler extends React.Component {
constructor(props) {
super(props);
this.state = { value: '', error: null };
}
handleChange = event => {
this.setState({ value: event.target.value });
};
handleSubmit = event => {
event.preventDefault();
if (this.state.value.length < 5) {
this.setState({ error: 'Value must be at least 5 characters long.' });
return;
}
this.setState({ error: null });
this.props.onSubmit(this.state.value);
};
render() {
return this.props.render({
value: this.state.value,
handleChange: this.handleChange,
handleSubmit: this.handleSubmit,
error: this.state.error
});
}
}
function MyComponent() {
return (
alert(`Submitted value: ${value}`)}
render={({ value, handleChange, handleSubmit, error }) => (
)}
/>
);
}
åœéçãªäœæåœ¢åŒã«å¯Ÿå¿ããããã«ããã©ãŒã ã®ããªããŒã·ã§ã³ã«ãŒã«ãé©å¿ãããããšãæ€èšããŠãã ãããFormHandler
ã³ã³ããŒãã³ãã¯æ±çšçãªãŸãŸã§ãrender propãç°ãªãå°åã®ããã®ç¹å®ã®ããªããŒã·ã§ã³ãšUIããžãã¯ãå®çŸ©ããŸãïŒ
sendAddressToServer(address)}
render={({ value, handleChange, handleSubmit, error }) => (
)}
/>
4. ãã£ãŒãã£ãŒãã©ã°ãšA/Bãã¹ã
Render Propsã¯ããã£ãŒãã£ãŒãã©ã°ã®ç®¡çãA/Bãã¹ãã®å®æœã«ã䜿çšã§ããŸããRender Propã³ã³ããŒãã³ãã¯ãçŸåšã®ãŠãŒã¶ãŒãã©ã³ãã ã«çæããããã©ã°ã«åºã¥ããŠãã©ã®ããŒãžã§ã³ã®æ©èœãæç»ããããæ±ºå®ã§ããŸãã
class FeatureFlag extends React.Component {
constructor(props) {
super(props);
this.state = { enabled: Math.random() < this.props.probability };
}
render() {
return this.props.render(this.state.enabled);
}
}
function MyComponent() {
return (
{
if (enabled) {
return New Feature!
;
} else {
return Old Feature
;
}
}}
/>
);
}
ã°ããŒãã«ãªå©çšè
ã察象ã«A/Bãã¹ããè¡ãå Žåãèšèªãå°åããŸãã¯ãã®ä»ã®äººå£çµ±èšããŒã¿ã«åºã¥ããŠãŠãŒã¶ãŒãã»ã°ã¡ã³ãåããããšãéèŠã§ããFeatureFlag
ã³ã³ããŒãã³ãã¯ããããã®èŠçŽ ãèæ
®ããŠãã©ã®ããŒãžã§ã³ã®æ©èœã衚瀺ããããæ±ºå®ããããã«å€æŽã§ããŸãïŒ
{
return isEnabled ? : ;
}}
/>
Render Propsã®ä»£æ¿æ¡ïŒé«éã³ã³ããŒãã³ãïŒHOCïŒãšããã¯
Render Propsã¯åŒ·åãªãã¿ãŒã³ã§ãããåæ§ã®çµæãéæã§ãã代æ¿ã¢ãããŒãããããŸãã2ã€ã®äžè¬çãªä»£æ¿æ¡ã¯ãé«éã³ã³ããŒãã³ãïŒHOCïŒãšããã¯ã§ãã
é«éã³ã³ããŒãã³ãïŒHOCïŒ
é«éã³ã³ããŒãã³ãïŒHOCïŒã¯ãã³ã³ããŒãã³ããåŒæ°ãšããŠåãåããæ°ãã匷åãããã³ã³ããŒãã³ããè¿ã颿°ã§ããHOCã¯äžè¬çã«ãæ¢åã®ã³ã³ããŒãã³ãã«æ©èœãããžãã¯ã远å ããããã«äœ¿çšãããŸãã
äŸãã°ãwithMouse
HOCã¯ãã³ã³ããŒãã³ãã«ããŠã¹ãã©ããã³ã°æ©èœãæäŸã§ããŸãïŒ
function withMouse(WrappedComponent) {
return class extends React.Component {
constructor(props) {
super(props);
this.state = { x: 0, y: 0 };
}
handleMouseMove = event => {
this.setState({ x: event.clientX, y: event.clientY });
};
render() {
return (
);
}
};
}
function MyComponent(props) {
return (
The mouse position is ({props.mouse.x}, {props.mouse.y})
);
}
const EnhancedComponent = withMouse(MyComponent);
HOCã¯ã³ãŒãã®åå©çšæ§ãæäŸããŸãããpropåã®è¡çªãåŒãèµ·ãããã³ã³ããŒãã³ãã®åæãããå°é£ã«ããå¯èœæ§ããããããã¯ãã©ãããŒå°çããšããŠç¥ãããçŸè±¡ã§ãã
ããã¯
React 16.8ã§å°å ¥ãããReactããã¯ã¯ãã³ã³ããŒãã³ãéã§ã¹ããŒããã«ãªããžãã¯ãåå©çšããããã®ããçŽæ¥çã§è¡šçŸåè±ããªæ¹æ³ãæäŸããŸããããã¯ã䜿çšãããšã颿°ã³ã³ããŒãã³ãããReactã®ç¶æ ãšã©ã€ããµã€ã¯ã«æ©èœã«ãããã¯ãããããšãã§ããŸãã
useMousePosition
ããã¯ã䜿çšãããšãããŠã¹ãã©ããã³ã°æ©èœã¯æ¬¡ã®ããã«å®è£
ã§ããŸãïŒ
import { useState, useEffect } from 'react';
function useMousePosition() {
const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 });
useEffect(() => {
function handleMouseMove(event) {
setMousePosition({ x: event.clientX, y: event.clientY });
}
window.addEventListener('mousemove', handleMouseMove);
return () => {
window.removeEventListener('mousemove', handleMouseMove);
};
}, []);
return mousePosition;
}
function MyComponent() {
const mousePosition = useMousePosition();
return (
The mouse position is ({mousePosition.x}, {mousePosition.y})
);
}
ããã¯ã¯ãRender PropsãHOCãšæ¯èŒããŠãã¹ããŒããã«ãªããžãã¯ãåå©çšããããã®ããã¯ãªãŒã³ã§ç°¡æœãªæ¹æ³ãæäŸããŸãããŸããã³ãŒãã®å¯èªæ§ãšä¿å®æ§ã®åäžãä¿é²ããŸãã
Render Props vs. ããã¯ïŒé©åãªããŒã«ã®éžæ
Render Propsãšããã¯ã®ã©ã¡ããéžæãããã¯ããããžã§ã¯ãã®ç¹å®ã®èŠä»¶ãšå人ã®å¥œã¿ã«ãã£ãŠç°ãªããŸãã以äžã«ããããã®äž»ãªéãã®æŠèŠã瀺ããŸãïŒ
- å¯èªæ§ïŒ ããã¯ã¯äžè¬çã«ãããèªã¿ãããç°¡æœãªã³ãŒãã«ã€ãªãããŸãã
- åæïŒ ããã¯ã¯ã³ã³ããŒãã³ãã®åæã容æã«ããHOCã«é¢é£ãããã©ãããŒå°çãã®åé¡ãåé¿ããŸãã
- ã·ã³ãã«ãïŒ ããã¯ã¯ãç¹ã«Reactã«æ £ããŠããªãéçºè ã«ãšã£ãŠãçè§£ãããã䜿ããããå ŽåããããŸãã
- ã¬ã¬ã·ãŒã³ãŒãïŒ Render Propsã¯ãå€ãã³ãŒãããŒã¹ãç¶æããå Žåããããã¯ã䜿çšããããã«æŽæ°ãããŠããªãã³ã³ããŒãã³ããæ±ãå Žåã«ãããé©ããŠããå¯èœæ§ããããŸãã
- å¶åŸ¡ïŒ Render Propsã¯ãã¬ã³ããªã³ã°ããã»ã¹ã«å¯Ÿããããæç€ºçãªå¶åŸ¡ãæäŸããŸããRender Propã³ã³ããŒãã³ãã«ãã£ãŠæäŸãããããŒã¿ã«åºã¥ããŠãäœãã¬ã³ããªã³ã°ããããæ£ç¢ºã«æ±ºå®ã§ããŸãã
Render Propsã䜿çšããããã®ãã¹ããã©ã¯ãã£ã¹
Render Propsãã¿ãŒã³ã广çã«äœ¿çšããã«ã¯ã次ã®ãã¹ããã©ã¯ãã£ã¹ãèæ ®ããŠãã ããïŒ
- Render Prop颿°ãã·ã³ãã«ã«ä¿ã€ïŒ render prop颿°ã¯ãæäŸãããããŒã¿ã«åºã¥ããŠUIãã¬ã³ããªã³ã°ããããšã«éäžããè€éãªããžãã¯ãé¿ããã¹ãã§ãã
- 説æçãªPropåã䜿çšããïŒ propã®ç®çãæç¢ºã«ç€ºãããã«ã説æçãªpropåïŒäŸïŒ
render
ãchildren
ãcomponent
ïŒãéžæããŸãã - äžèŠãªåã¬ã³ããªã³ã°ãé¿ããïŒ ç¹ã«é »ç¹ã«å€æŽãããããŒã¿ãæ±ãå ŽåãäžèŠãªåã¬ã³ããªã³ã°ãé¿ããããã«Render Propã³ã³ããŒãã³ããæé©åããŸããpropsã倿ŽãããŠããªãå Žåã«åã¬ã³ããªã³ã°ãé²ãããã«ã
React.memo
ãŸãã¯shouldComponentUpdate
ã䜿çšããŸãã - ã³ã³ããŒãã³ããææžåããïŒ Render Propã³ã³ããŒãã³ãã®ç®çãšäœ¿ç𿹿³ïŒæåŸ ãããããŒã¿ãå©çšå¯èœãªpropsãå«ãïŒãæç¢ºã«ææžåããŸãã
çµè«
Render Propsãã¿ãŒã³ã¯ãæè»ã§åå©çšå¯èœãªReactã³ã³ããŒãã³ããæ§ç¯ããããã®è²Žéãªãã¯ããã¯ã§ããããžãã¯ãã«ãã»ã«åããrender propãä»ããŠã³ã³ããŒãã³ãã«æäŸããããšã§ãã³ãŒãã®åå©çšæ§ãã³ã³ããŒãã³ãã®åæãé¢å¿ã®åé¢ãä¿é²ã§ããŸããããã¯ã¯ããã¢ãã³ã§ããã°ãã°ããã·ã³ãã«ãªä»£æ¿æ¡ãæäŸããŸãããRender Propsã¯ãç¹ã«ã¬ã¬ã·ãŒã³ãŒããã¬ã³ããªã³ã°ããã»ã¹ã«å¯Ÿãããã现ãããªå¶åŸ¡ãå¿ èŠãªã·ããªãªãæ±ãå Žåã«ãReactéçºè ã®æŠåšåº«ã«ãã匷åãªããŒã«ã§ããç¶ããŸãã
Render Propsãã¿ãŒã³ã®å©ç¹ãšãã¹ããã©ã¯ãã£ã¹ãçè§£ããããšã§ã倿§ãªã°ããŒãã«ãªå©çšè ã«åããå ç¢ã§é©å¿æ§ã®é«ãã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ã§ããç°ãªãå°åãæåã«ããã£ãŠäžè²«ããé åçãªãŠãŒã¶ãŒãšã¯ã¹ããªãšã³ã¹ãä¿èšŒã§ããŸããéèŠãªã®ã¯ããããžã§ã¯ãã®ç¹å®ã®ããŒãºãšããŒã ã®å°éç¥èã«åºã¥ããŠãé©åãªãã¿ãŒã³ïŒRender PropsãHOCããŸãã¯ããã¯ïŒãéžæããããšã§ããã¢ãŒããã¯ãã£äžã®æ±ºå®ãè¡ãéã«ã¯ãåžžã«ã³ãŒãã®å¯èªæ§ãä¿å®æ§ãããã³ããã©ãŒãã³ã¹ãåªå ããããšãå¿ããªãã§ãã ããã